﻿using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using iWare.Wms.Core;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Yitter.IdGenerator;

namespace iWare.Wms.Application.PDA
{
    /// <summary>
    /// 物料收货,送货单查询服务
    /// </summary>
    [Route("api/MaterialCollect")]
    [ApiDescriptionSettings("PDA", Name = "MaterialCollect", Order = 100)]

    public class MaterialCollectService : ControllerBase, IDynamicApiController, ITransient
    {
        private readonly IRepository<GoodsDelivery, MasterDbContextLocator> _goodsDeliveryRep; //送货单仓储
        private readonly IRepository<GoodsDeliveryDetails, MasterDbContextLocator> _goodsDeliveryDetailsRep; //送货单明细仓储
        private readonly IRepository<CollectDelivery, MasterDbContextLocator> _collectDeliveryRep; //收货单仓储
        private readonly IRepository<CollectDeliveryDetails, MasterDbContextLocator> _collectDeliveryDetailsRep; //收货单明细仓储
        private readonly IRepository<GoodsDeliveryVsCollectDelivery, MasterDbContextLocator> _goodsDeliveryVsCollectDeliveryRep; //送货单与收货单关系仓储
        private readonly IRepository<SupplierExamineFlower, MasterDbContextLocator> _supplierExamineFlowerRep; //送货单审核记录仓储

        #region 默认
        /// <summary>
        /// 默认
        /// </summary>
        /// <param name="goodsDeliveryRep"></param>
        /// <param name="goodsDeliveryDetailsRep"></param>
        /// <param name="collectDeliveryRep"></param>
        /// <param name="collectDeliveryDetailsRep"></param>
        /// <param name="goodsDeliveryVsCollectDeliveryRep"></param>
        /// <param name="supplierExamineFlowerRep"></param>
        public MaterialCollectService(
            IRepository<GoodsDelivery, MasterDbContextLocator> goodsDeliveryRep,
            IRepository<GoodsDeliveryDetails, MasterDbContextLocator> goodsDeliveryDetailsRep,
            IRepository<CollectDelivery, MasterDbContextLocator> collectDeliveryRep,
            IRepository<CollectDeliveryDetails, MasterDbContextLocator> collectDeliveryDetailsRep,
            IRepository<GoodsDeliveryVsCollectDelivery, MasterDbContextLocator> goodsDeliveryVsCollectDeliveryRep,
            IRepository<SupplierExamineFlower, MasterDbContextLocator> supplierExamineFlowerRep
        )
        {
            _goodsDeliveryRep = goodsDeliveryRep;
            _goodsDeliveryDetailsRep = goodsDeliveryDetailsRep;
            _collectDeliveryRep = collectDeliveryRep;
            _collectDeliveryDetailsRep = collectDeliveryDetailsRep;
            _goodsDeliveryVsCollectDeliveryRep = goodsDeliveryVsCollectDeliveryRep;
            _supplierExamineFlowerRep = supplierExamineFlowerRep;
        }
        #endregion

        #region
        /// <summary>
        /// 扫描物料二维码(弃用)
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("GetCollectByScann")]
        public async Task<List<MaterialDto>> GetCollectByScann([FromBody] MaterialCollectInput input)
        {
            if (input.ScannMaterial == null) throw Oops.Oh("请扫描物料二维码！");

            //检查重复物料
            var collectModel = input.CollectMaterials.Where(p =>
            p.DeliveryNo == input.ScannMaterial.DeliveryNo.Trim() && p.ProjectCode == input.ScannMaterial.ProjectCode.Trim() && p.Code == input.ScannMaterial.Code.Trim())
                .Where(!string.IsNullOrEmpty(input.ScannMaterial.XuHao.Trim()), p => p.XuHao == input.ScannMaterial.XuHao.Trim()).FirstOrDefault();
            if (collectModel != null && collectModel.DeliveryQuantity < collectModel.ThisQuantity + collectModel.CollectQuantity + input.ScannMaterial.ThisQuantity)
                throw Oops.Oh("物料已经收货");

            //检查送货中是否存物料信息
            var deliveryModel = await _goodsDeliveryDetailsRep.DetachedEntities.Where(p => p.GoodsDelivery.DeliveryNo == input.ScannMaterial.DeliveryNo.Trim()
            && p.ProjectCode == input.ScannMaterial.ProjectCode.Trim() && p.Code == input.ScannMaterial.Code.Trim())
                .Where(!string.IsNullOrEmpty(input.ScannMaterial.XuHao.Trim()), p => p.XuHao == input.ScannMaterial.XuHao.Trim())
                .FirstOrDefaultAsync();
            if (deliveryModel == null) throw Oops.Oh("该送货单[" + input.ScannMaterial.DeliveryNo + "]中无此物料!");

            //获取收货集合中本次收货总数量
            var collectListQuantity = input.CollectMaterials.Where(p => p.DeliveryNo == input.ScannMaterial.DeliveryNo.Trim() &&
            p.ProjectCode == input.ScannMaterial.ProjectCode.Trim() && p.Code == input.ScannMaterial.Code.Trim())
                .Where(!string.IsNullOrEmpty(input.ScannMaterial.XuHao.Trim()), p => p.XuHao == input.ScannMaterial.XuHao.Trim())
                .Sum(n => n.ThisQuantity);

            //获取收货表中数量
            var collectTableQuantity = await _collectDeliveryDetailsRep.DetachedEntities.Where(p => p.CollectDelivery.DeliveryNo == input.ScannMaterial.DeliveryNo.Trim()
            && p.ProjectCode == input.ScannMaterial.ProjectCode.Trim() && p.Code == input.ScannMaterial.Code.Trim())
            .Where(!string.IsNullOrEmpty(input.ScannMaterial.XuHao.Trim()), p => p.XuHao == input.ScannMaterial.XuHao.Trim())
            .SumAsync(n => n.CollectQuantity);

            //收货表中数量==送货数
            if (collectTableQuantity == deliveryModel.DeliveryQuantity) throw Oops.Oh("送货单[" + input.ScannMaterial.DeliveryNo.Trim() + "]中该物料已收货完成!");

            //收货表中数量+收货集合中数量==送货数
            if (collectTableQuantity + collectListQuantity == deliveryModel.DeliveryQuantity) throw Oops.Oh("送货单[" + input.ScannMaterial.DeliveryNo.Trim() + "]中该物料已收货完成!");

            //已收货数量+物料标签数量>送货数
            if (collectTableQuantity + collectListQuantity + input.ScannMaterial.ThisQuantity > deliveryModel.DeliveryQuantity) throw Oops.Oh("送货单[" + input.ScannMaterial.DeliveryNo.Trim() + "]中该物料数量异常!");

            var qualityResultName = string.Empty; //质检结果
            // 查询是否已收货信息
            var collectDeliveryDetailsModel = await _collectDeliveryDetailsRep.FirstOrDefaultAsync(p => p.CollectDelivery.DeliveryNo == input.ScannMaterial.DeliveryNo.Trim()
            && p.ProjectCode == input.ScannMaterial.ProjectCode.Trim() && p.Code == input.ScannMaterial.Code.Trim());

            //构建收货对象
            var newItem = deliveryModel.Adapt<MaterialDto>();
            newItem.ThisQuantity = deliveryModel.DeliveryQuantity - collectTableQuantity;
            newItem.CollectQuantity = newItem.CollectQuantity = deliveryModel.CollectQuantity;
            newItem.DeliveryNo = input.ScannMaterial.DeliveryNo.Trim();
            newItem.QualityResultName = qualityResultName;
            if (collectModel != null)
            {
                newItem.ThisQuantity += collectModel.ThisQuantity;
                input.CollectMaterials.Remove(collectModel);
            }
            input.CollectMaterials.Insert(0, newItem);
            return input.CollectMaterials;
        }
        #endregion

        /// <summary>
        /// 点击下一步返回已收和缺料物料集合
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("ReturnCollectList")]
        public async Task<List<ReturnCollectOutput>> ReturnCollectList([FromBody] List<MaterialDto> input)
        {
            if (input.Count == 0) throw Oops.Oh("物料信息不能为空！");
            // 根据送货单号去重
            var deliveryNoDistincts = input.Select(t => t.DeliveryNo).Distinct().ToList();

            // 创建返回集合
            var MaterialCollectList = new List<ReturnCollectOutput>();
            foreach (var deliveryNo in deliveryNoDistincts)
            {
                // 获取的收货集合物料明细
                var scannCollectDetailsList = input.Where(n => n.DeliveryNo == deliveryNo).ToList().Adapt<List<MaterialOutput>>();

                //获取收货表中的明细
                var collectTableDetailsList = await _collectDeliveryDetailsRep.DetachedEntities.Where(
                    p => p.CollectDelivery.DeliveryNo == deliveryNo).ProjectToType<MaterialOutput>().ToListAsync();

                //更新收货集合表
                foreach (var itemsub in scannCollectDetailsList)
                {
                    var model = collectTableDetailsList.Where(p => p.ProjectCode == itemsub.ProjectCode
                        && p.Code == itemsub.Code && p.SpecificationModel == itemsub.SpecificationModel)
                        .Where(!string.IsNullOrEmpty(itemsub.XuHao), p => p.XuHao == itemsub.XuHao).FirstOrDefault();

                    if (model == null)
                    {
                        itemsub.CollectQuantity = itemsub.ThisQuantity;
                        collectTableDetailsList.Add(itemsub);
                    }
                    else
                    {
                        itemsub.CollectQuantity = model.CollectQuantity + itemsub.ThisQuantity;
                        collectTableDetailsList.Remove(model);
                        collectTableDetailsList.Add(itemsub);
                    }
                }

                var deliveryDetailsList = await _goodsDeliveryDetailsRep.DetachedEntities
                   .Where(p => p.GoodsDelivery.DeliveryNo == deliveryNo).ProjectToType<MaterialOutput>().ToListAsync();

                //获取缺料列表
                var notcollectTableDetailsList = new List<MaterialOutput>();
                foreach (var itemsub in deliveryDetailsList)
                {
                    var model = collectTableDetailsList.Where(p => p.ProjectCode == itemsub.ProjectCode
                          && p.Code == itemsub.Code && p.SpecificationModel == itemsub.SpecificationModel)
                          .Where(!string.IsNullOrEmpty(itemsub.XuHao), p => p.XuHao == itemsub.XuHao).FirstOrDefault();

                    if (model == null)
                    {
                        itemsub.CollectQuantity = itemsub.DeliveryQuantity;
                        notcollectTableDetailsList.Add(itemsub);
                    }
                    else
                    {
                        if (model.CollectQuantity > itemsub.DeliveryQuantity) throw Oops.Oh("送货单[" + deliveryNo + "]物料品号[" + model.Code + "]数据异常！");
                        if (model.CollectQuantity < itemsub.DeliveryQuantity)
                        {
                            itemsub.CollectQuantity = itemsub.DeliveryQuantity - model.CollectQuantity;
                            notcollectTableDetailsList.Add(itemsub);
                        }
                    }
                }

                var returnModel = new ReturnCollectOutput()
                {
                    DeliveryNo = deliveryNo,
                    DeliveryQuantity = deliveryDetailsList.Sum(t => t.DeliveryQuantity),
                    CollectQuantity = collectTableDetailsList.Sum(t => t.CollectQuantity),
                    collectDetailss = collectTableDetailsList,
                    notCollectDetailss = notcollectTableDetailsList
                };

                //构建返回集合中对象
                MaterialCollectList.Add(returnModel);
            }

            return MaterialCollectList;
        }

        /// <summary>
        /// 新增采购收货
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("AddMaterial")]
        [UnitOfWork]
        public async Task AddMaterial([FromBody] List<MaterialInput> input)
        {
            if (input.Count == 0) throw Oops.Oh("物料信息不能为空！");
            // 根据送货单号去重
            var deliveryNoDistincts = input.Select(t => t.DeliveryNo).Distinct().ToList();

            foreach (var deliveryNo in deliveryNoDistincts)
            {
                // 获取的收货集合物料明细
                var scannCollectDetailsList = input.Where(n => n.DeliveryNo == deliveryNo).ToList().Adapt<List<CollectDeliveryDetailsDto>>();
                var goodsDeliveryModel = await _goodsDeliveryRep.FirstOrDefaultAsync(p => p.DeliveryNo == deliveryNo);
                if (goodsDeliveryModel == null) throw Oops.Oh("送货单号不存在!");

                var collectDeliveryModel = await _collectDeliveryRep.DetachedEntities
                    .Where(n => n.DeliveryNo == deliveryNo).ProjectToType<CollectDelivery>().FirstOrDefaultAsync();
                if (collectDeliveryModel == null)
                {
                    // 构建收货主表
                    collectDeliveryModel = new CollectDelivery()
                    {
                        SupplierInfoCode = goodsDeliveryModel.SuppCode.Trim(),
                        CollectNo = YitIdHelper.NextId().ToString(), //系统生成收货单号
                        DeliveryNo = deliveryNo,
                        ProjectCode = goodsDeliveryModel.ProjectCode,
                        CollectType = goodsDeliveryModel.DeliveryType,
                        CollectQuantityTotal = scannCollectDetailsList.Sum(t => t.ThisQuantity),
                    };
                    await _collectDeliveryRep.InsertNowAsync(collectDeliveryModel);

                    //新增送货单与收货单关系
                    var vsitem = new GoodsDeliveryVsCollectDelivery()
                    {
                        CollectDeliveryId = collectDeliveryModel.Id,
                        GoodsDeliveryId = goodsDeliveryModel.Id,
                    };
                    await _goodsDeliveryVsCollectDeliveryRep.InsertAsync(vsitem);
                }

                // 遍历收货详情
                foreach (var itemsub in scannCollectDetailsList)
                {
                    //新增收货数据
                    var deliveryDetailsModel = await _collectDeliveryDetailsRep.FirstOrDefaultAsync(p =>
                    p.ProjectCode == itemsub.ProjectCode && p.Code == itemsub.Code && p.CollectDelivery.DeliveryNo == deliveryNo);

                    if (deliveryDetailsModel == null)
                    {
                        itemsub.CollectQuantity = itemsub.ThisQuantity;
                        itemsub.SupplierInfoCode = goodsDeliveryModel.SuppCode.Trim();
                        itemsub.CollectDeliveryId = collectDeliveryModel.Id;
                        itemsub.IsWarehousing = YesOrNot.N;
                        itemsub.IsQuality = YesOrNot.N;
                        //itemsub.QualityResult = 0; //枚举类型
                        await _collectDeliveryDetailsRep.InsertAsync(itemsub.Adapt<CollectDeliveryDetails>());
                    }
                    else
                    {
                        deliveryDetailsModel.CollectQuantity += itemsub.ThisQuantity;
                        await _collectDeliveryDetailsRep.UpdateAsync(deliveryDetailsModel);
                    }

                    //更改送货状态详情
                    var model = await _goodsDeliveryDetailsRep.FirstOrDefaultAsync(p =>
                    p.ProjectCode == itemsub.ProjectCode && p.Code == itemsub.Code && p.GoodsDelivery.DeliveryNo == deliveryNo);
                    if (model != null)
                    {
                        model.CollectQuantity += itemsub.ThisQuantity;
                        await _goodsDeliveryDetailsRep.UpdateAsync(model);
                    }
                }

                //判断送货数量和收货数量是否相等,如果相等更改对应单据状态
                var totalCollectNumber = await _collectDeliveryDetailsRep.Where(p => p.CollectDelivery.DeliveryNo == deliveryNo).SumAsync(n => n.CollectQuantity);
                if (totalCollectNumber == goodsDeliveryModel.DeliveryQuantityTotal)
                {
                    //创建审批记录
                    var supplierExaminerFlowerModel = new SupplierExamineFlower()
                    {
                        Status = AuditStatusEnum.songhuowancheng, //送货完成
                        DeliveryID = goodsDeliveryModel.Id,
                        Remarks = "送货完成"
                    };
                    await _supplierExamineFlowerRep.InsertAsync(supplierExaminerFlowerModel);

                    // 更新送货状态为“送货完成”
                    goodsDeliveryModel.Status = AuditStatusEnum.songhuowancheng;
                    await _goodsDeliveryRep.UpdateAsync(goodsDeliveryModel);
                }
            }
        }

        /// <summary>
        /// 查询收货
        /// </summary>
        /// <returns></returns>
        [HttpGet("GetReceipt")]
        public async Task<ReturnCollectOutput> GetReceipt([FromQuery] CollectSearchInput input)
        {
            if (string.IsNullOrEmpty(input.DeliveryNo)) throw Oops.Oh("请扫描送货单号！");

            var deliveryDetailsList = await _goodsDeliveryDetailsRep.DetachedEntities
            .Where(p => p.GoodsDelivery.DeliveryNo == input.DeliveryNo).ProjectToType<MaterialOutput>().ToListAsync();
            if (deliveryDetailsList.Count == 0) throw Oops.Oh("送货单号不存在!");

            //获取收货表中的明细
            var collectTableDetailsList = await _collectDeliveryDetailsRep.DetachedEntities.Where(
                p => p.CollectDelivery.DeliveryNo == input.DeliveryNo).ProjectToType<MaterialOutput>().ToListAsync();

            var newcollectTableDetailsList = new List<MaterialOutput>();
            foreach (var item in collectTableDetailsList)
            {
                var collectModel = newcollectTableDetailsList.FirstOrDefault(p => p.ProjectCode == item.ProjectCode
                && p.Code == item.Code && p.SpecificationModel == item.SpecificationModel);

                if (collectModel == null) newcollectTableDetailsList.Add(item);
                else
                {
                    collectModel.CollectQuantity += item.CollectQuantity;
                }
            }

            //获取缺料列表
            var notcollectTableDetailsList = new List<MaterialOutput>();
            foreach (var itemsub in deliveryDetailsList)
            {
                var model = newcollectTableDetailsList.FirstOrDefault(p => p.ProjectCode == itemsub.ProjectCode
                && p.Code == itemsub.Code && p.SpecificationModel == itemsub.SpecificationModel);
                if (model == null)
                {
                    itemsub.CollectQuantity = itemsub.DeliveryQuantity;
                    itemsub.DeliveryQuantity = itemsub.DeliveryQuantity;
                    notcollectTableDetailsList.Add(itemsub);
                }
                else
                {
                    model.DeliveryQuantity = itemsub.DeliveryQuantity;

                    if (model.CollectQuantity > itemsub.DeliveryQuantity) throw Oops.Oh("送货单[" + input.DeliveryNo + "]物料品号[" + model.Code + "]数据异常！");
                    if (model.CollectQuantity < itemsub.DeliveryQuantity)
                    {
                        itemsub.DeliveryQuantity = itemsub.DeliveryQuantity;
                        itemsub.CollectQuantity = itemsub.DeliveryQuantity - model.CollectQuantity;
                        notcollectTableDetailsList.Add(itemsub);
                    }
                }
            }

            return new ReturnCollectOutput()
            {
                DeliveryNo = input.DeliveryNo,
                DeliveryQuantity = deliveryDetailsList.Sum(t => t.DeliveryQuantity),
                CollectQuantity = newcollectTableDetailsList.Sum(t => t.CollectQuantity),
                collectDetailss = newcollectTableDetailsList,
                notCollectDetailss = notcollectTableDetailsList
            };
        }

        /// <summary>
        /// 2023-3-16 新增 采购收货扫描送货单
        /// </summary>
        /// <returns></returns>
        [HttpGet("ScanOrder")]
        public async Task<GoodsDeliveryOutput> ScanOrder([FromQuery] CollectSearchInput input)
        {
            if (string.IsNullOrEmpty(input.DeliveryNo)) throw Oops.Oh("请扫描送货单号！");

            var deliveryModel = await _goodsDeliveryRep.DetachedEntities
                .Where(p => p.DeliveryNo == input.DeliveryNo)
                .ProjectToType<GoodsDeliveryOutput>().FirstOrDefaultAsync();
            if (deliveryModel == null) throw Oops.Oh("送货单号不存在!");

            if (deliveryModel != null && deliveryModel.Status == AuditStatusEnum.songhuowancheng) throw Oops.Oh("送货单号已收货完成!");

            return deliveryModel;
        }

        /// <summary>
        /// 2023-3-16 新增 采购收货扫描物料
        /// </summary>
        /// <returns></returns>
        [HttpPost("ScanMatter")]
        public async Task<List<MaterialDto>> ScanMatter([FromBody] MaterialCollectInput input)
        {
            if (input == null) throw Oops.Oh("请扫描物料二维码！");
            //检查重复物料
            var collectModel = input.CollectMaterials.Where(p => p.Code == input.ScannMaterial.Code.Trim()).FirstOrDefault();
            if (collectModel != null) throw Oops.Oh("物料已扫描");

            //获取送货表中数量
            var goodsTableQuantity = await _goodsDeliveryDetailsRep.DetachedEntities.Where(p => p.GoodsDelivery.DeliveryNo == input.DeliveryNo.Trim())
            .SumAsync(n => n.DeliveryQuantity);
            //检查送货中是否存物料信息
            var deliveryModel = await _goodsDeliveryDetailsRep.DetachedEntities
                .Where(p => p.GoodsDelivery.DeliveryNo == input.DeliveryNo.Trim() && p.Code == input.ScannMaterial.Code.Trim()).FirstOrDefaultAsync();
            if (deliveryModel == null) throw Oops.Oh("该送货单[" + input.DeliveryNo + "]中无此物料!");

            //获取收货表中数量
            var collectTableQuantity = await _collectDeliveryDetailsRep.DetachedEntities.Where(p => p.CollectDelivery.DeliveryNo == input.DeliveryNo.Trim())
            .SumAsync(n => n.CollectQuantity);

            //收货表中数量==送货数
            if (collectTableQuantity == goodsTableQuantity) throw Oops.Oh("送货单[" + input.DeliveryNo.Trim() + "]中该物料已收货完成!");

            //已收货数量+物料标签数量>送货数
            if (collectTableQuantity + input.ScannMaterial.ThisQuantity > goodsTableQuantity) throw Oops.Oh("送货单[" + input.DeliveryNo.Trim() + "]中该物料数量异常!");

            var qualityResultName = string.Empty; //质检结果
            // 查询是否已收货信息
            var collectDeliveryDetailsModel = await _collectDeliveryDetailsRep.FirstOrDefaultAsync(p => p.CollectDelivery.DeliveryNo == input.DeliveryNo.Trim()
            && p.Code == input.ScannMaterial.Code.Trim());

            //构建收货对象
            var newItem = deliveryModel.Adapt<MaterialDto>();
            newItem.ThisQuantity = deliveryModel.DeliveryQuantity;
            newItem.CollectQuantity = newItem.CollectQuantity = deliveryModel.CollectQuantity;
            newItem.DeliveryNo = input.DeliveryNo.Trim();
            newItem.QualityResultName = qualityResultName;
            if (collectModel != null)
            {
                newItem.ThisQuantity += collectModel.ThisQuantity;
                input.CollectMaterials.Remove(collectModel);
            }
            input.CollectMaterials.Insert(0, newItem);
            return input.CollectMaterials;
        }
    }
}
